// Jumble.cpp : Defines the entry point for the console application.
//

#include "StdAfx.h"
#include <iostream>
#include <string>
#include <fstream>
#include "Dictionary.h"
#include "Word.h"
#include "Request.h"
#include <time.h>

using namespace std;

int usage()
{
	cerr << "Usage: " << endl;
	cerr << "\tJumble [DictionaryFileName], [SearchFileName]\r\n" << endl;
	cerr << "Press any key to exit."  << endl;
	cin.get();
	return 1;
}

void Clear(list< CWord* > & wordList)
{
	for(list<CWord*>::iterator itr = wordList.begin();
					itr != wordList.end(); itr++)
	{
		delete *itr;
	}
	wordList.clear();
}

void Clone(list< CWord* > & set1, list< CWord* > & set2)
{
	if (!set2.empty())
	{
		for(list<CWord*>::iterator itr1 = set1.begin(); itr1 != set1.end(); itr1++)
		{
			delete *itr1;
		}
		set1.clear();

		for(list<CWord*>::iterator itr2 = set2.begin(); itr2 != set2.end(); itr2++)
		{
			CWord *pWord = new CWord(*(*itr2));
			set1.push_back( pWord );
		}
	}
}

int main(int argc, char* argv[])
{
	if (argc != 3)
	{
		return  usage();
	}

	const string dictionary_FileName = argv[1];// "C:\\Work\\algorithms\\Jumble\\EnglishWordList.txt";

	CDictionary dict;
	if (dict.ReadWordsFromFiles(dictionary_FileName))
	{
		//cout << "\r\nPress any key to continue..." << endl;
		//cin.get();
		time_t startTime = time(NULL);

		try
		{
			const string fileName = argv[2];//"C:\\Work\\algorithms\\Jumble\\input.txt";;
			cout << "loading from " << fileName << "\r\n" << endl;

			ifstream inputFile;
			inputFile.open(fileName.c_str());

			if (inputFile.is_open())
			{
				string line;
				while (getline(inputFile, line))
				{
					cout << "search: " << line << "\r\n=================================\r\n" << endl;
					cout << "result: " << endl;

					CRequest req(line);
					map<char, int> goal = req.GetKeys();
					
					vector<list<CWord*>> wordList;
					bool found = req.GetCandidates(wordList, &dict);
					if (!found)
					{
						cout << "can not find Jumble words!" << endl;
					}
					else
					{
						list< CWord* > target;
						Clone(target, wordList[0]);
						int index = wordList.size();
						for(int i=1; i < index - 1 ; ++i)
						{
							list< CWord* > swap;
							
							for(list<CWord*>::iterator itr2 = wordList[i].begin();
									itr2 != wordList[i].end(); itr2++)
							{
								for(list<CWord*>::iterator itr1 = target.begin();
									 itr1 != target.end(); itr1++)	
								{
									map<char,int> tmpMap = CWord::Add( (*itr1)->GetKeys(), (*itr2)->GetKeys());
									if (CWord::IsSubSet(tmpMap, goal))
									{
										string keyIds = CWord::GetKeyId(tmpMap);
										CWord *pWord = new CWord("", tmpMap, keyIds);
										pWord->MergeWords((*itr1)->GetWordList(), (*itr2)->GetWordList());
							
										//cout << (pWord)->GetKeyId() << endl;
										//cout << (pWord)->ToString() << endl;

										swap.push_back(pWord);
									}
								}
							}

							Clear(target);
							
							for(list<CWord*>::iterator itr = swap.begin(); 
								itr != swap.end(); itr++)
							{
								target.push_back( *itr );
							}
							swap.clear();
								
						}

						//cout << "----------------------------" << endl;

						//for(list<CWord*>::iterator itr = target.begin();
						//			 itr != target.end(); itr++)
						//{
						//	cout << (*itr)->GetKeyId() << endl;
						//	cout << (*itr)->ToString() << endl;
						//}

						if (dict.Search(target, wordList[index-1], goal) == 0)
						{
							cout << "can not find Jumble words!" << endl;
						}

						//free target
						Clear(target);
					}
					
				}
			}
			else
			{
				cerr << "loaded failed"  << endl;
			}
		}
		catch(exception &e)
		{
			cerr << e.what() << endl;
			throw e;
		}

		time_t endTime = time(NULL);
		cout << "search Elapsed: "  << difftime(endTime, startTime) <<  " seconds." << endl;

		return 0;
	}

	return -1;
}

